using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using igp.net.DataModel;

namespace igp.net.DataModel
{
    /// <summary>
    /// Represent the axes object.
    /// </summary>
    public class IgpAxes : IgpItem
    {
        /// <summary>
        /// Axes x coordinate for linear x scale.
        /// </summary>
        public double XCoordinateLinear { get; set; }

        /// <summary>
        /// Axes y coordinate for linear y scale.
        /// </summary>
        public double YCoordinateLinear { get; set; }

        /// <summary>
        /// Axes x coordinate for logarythmic x scale.
        /// </summary>
        public double XCoordinateLogarythmic { get; set; }

        /// <summary>
        /// Axes y coordinate for logarythmic y scale.
        /// </summary>
        public double YCoordinateLogarythmic { get; set; }

        private double linXo;

        private double linYo;

        private double logXo;

        private double logYo;

        private bool EditedX;

        private bool EditedY;

        /// <summary>
        /// Determines whether X axis will be drawn or not.
        /// </summary>
        public bool DrawAxisX { get; set; }

        /// <summary>
        /// Determines whether Y axis will be drawn or not.
        /// </summary>
        public bool DrawAxisY { get; set; }

        /// <summary>
        /// Draws the axes.
        /// </summary>
        /// <param name="graph">Graphics object used for painting</param>
        public override void Draw(Graphics graph)
        {
            IgpView currentView = IgpProject.Singleton.View;

            double X = XCoordinateLinear;
            if (currentView.LogScaleX) X = XCoordinateLogarythmic;

            double Y = YCoordinateLinear;
            if (currentView.LogScaleY) Y = YCoordinateLogarythmic;

            Point[] temp = new Point[3];

            //Draw horizontal axis
            SolidBrush lineBrush = new SolidBrush(LineColor);

            if (DrawAxisX)
            {
                graph.DrawLine(new Pen(LineColor, 2),
                               0, currentView.GetScreenCoordinateY(Y),
                               currentView.Width, currentView.GetScreenCoordinateY(Y));

                //Set coordinates of the horizontal arrow
                temp[0].X = currentView.Width;
                temp[0].Y = currentView.GetScreenCoordinateY(Y);
                temp[1].X = currentView.Width - 5;
                temp[1].Y = currentView.GetScreenCoordinateY(Y) - 5;
                temp[2].X = currentView.Width - 5;
                temp[2].Y = currentView.GetScreenCoordinateY(Y) + 5;

                //Draw the horizonral arrow
                graph.FillPolygon(lineBrush, temp);
            }

            //Draw vertical axis
            if (DrawAxisY)
            {
                graph.DrawLine(new Pen(LineColor, 2),
                               currentView.GetScreenCoordinateX(X), 0,
                               currentView.GetScreenCoordinateX(X), currentView.Height);

                //Set coordinates of the vertical arrow
                temp[0].X = currentView.GetScreenCoordinateX(X);
                temp[0].Y = 0;
                temp[1].X = currentView.GetScreenCoordinateX(X) - 5;
                temp[1].Y = 5;
                temp[2].X = currentView.GetScreenCoordinateX(X) + 5;
                temp[2].Y = 5;

                //Draw the vertical arrow
                graph.FillPolygon(lineBrush, temp);

                //When being edited

                if (EditedX)
                {
                    graph.DrawString("Y: " + Math.Round(Y, 4),
                                     igpSettings.Singleton.ChartFont,
                                     lineBrush,
                                     Math.Min(currentView.Width - 50, Math.Max(25, currentView.GetScreenCoordinateX(X) + 10)),
                                     Math.Min(currentView.Height - 25, Math.Max(15, currentView.GetScreenCoordinateY(Y) - 15)));
                }

                if (EditedY)
                {
                    graph.DrawString("X: " + Math.Round(X, 4),
                                     igpSettings.Singleton.ChartFont,
                                     lineBrush,
                                     Math.Min(currentView.Width - 50, Math.Max(25, currentView.GetScreenCoordinateX(X) + 10)),
                                     Math.Min(currentView.Height - 35, Math.Max(5, currentView.GetScreenCoordinateY(Y) - 25)));
                }
            }

        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        public IgpAxes()
        {
            Defaults();

        }

        /// <summary>
        /// Resets settings of the axes object.
        /// </summary>
        public void Defaults()
        {
            XCoordinateLinear = 0;
            YCoordinateLinear = 0;
            XCoordinateLogarythmic = 1;
            YCoordinateLogarythmic = 1;
            LineColor = Color.Black;
            DrawAxisX = true;
            DrawAxisY = true;
            EditedX = false;
            EditedY = false;
        }

        /// <summary>
        /// This method is required for item's reaction to mouse buttons being pressed. 
        /// You must invoke this base method in your derived class in order 
        /// to update some useful properties.
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractDown(Graphics graph, MouseEventArgs e)
        {
            base.InteractDown(graph, e);
            
            if (InteractionInUse) return;

            IgpView View = IgpProject.Singleton.View;

            double X = !View.LogScaleX ? XCoordinateLinear : XCoordinateLogarythmic;
            double Y = !View.LogScaleY ? YCoordinateLinear : YCoordinateLogarythmic;

            int AxisScreenX = (int)(View.GetScreenCoordinateX(X) * IgpProject.Singleton.View.GetRatioX());
            int AxisScreenY = (int)(View.GetScreenCoordinateY(Y) * IgpProject.Singleton.View.GetRatioY());


            if (e.X > AxisScreenX - 5 && e.X < AxisScreenX + 5 && e.Button == MouseButtons.Left && DrawAxisY)
            {
                EditedY = true;
                InteractionInUse = true;
            }

            if (e.Y > AxisScreenY - 5 && e.Y < AxisScreenY + 5 && e.Button == MouseButtons.Left && DrawAxisX)
            {
                EditedX = true;
                InteractionInUse = true;
            }

            linXo = XCoordinateLinear;
            linYo = YCoordinateLinear;
            logXo = XCoordinateLogarythmic;
            logYo = YCoordinateLogarythmic;
        }

        /// <summary>
        /// This method is required for item's reaction to mouse movement. 
        /// You must invoke this base method in your derived class in order 
        /// to update some useful properties.
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractMove(Graphics graph, MouseEventArgs e)
        {
            base.InteractMove(graph, e);

            IgpView currentView = IgpProject.Singleton.View;
            IgpView View = currentView;

            double X = !View.LogScaleX ? XCoordinateLinear : XCoordinateLogarythmic;
            double Y = !View.LogScaleY ? YCoordinateLinear : YCoordinateLogarythmic;

            int AxisScreenX = (int)(View.GetScreenCoordinateX(X) * currentView.GetRatioX());
            int AxisScreenY = (int)(View.GetScreenCoordinateY(Y) * currentView.GetRatioY());

            SolidBrush lineBrush = new SolidBrush(LineColor);

            if (e.X > AxisScreenX - 5 && e.X < AxisScreenX + 5 && !EditedY && !InteractionInUse && DrawAxisY)
            {
                graph.DrawLine(new Pen(Color.Red, 2),
                               currentView.GetScreenCoordinateX(X), 0,
                               currentView.GetScreenCoordinateX(X), currentView.Height);

                graph.DrawString("X: " + Math.Round(X, 4),
                                 igpSettings.Singleton.ChartFont,
                                 lineBrush,
                                 Math.Min(currentView.Width - 50, Math.Max(25, currentView.GetScreenCoordinateX(X) + 10)),
                                 Math.Min(currentView.Height - 35, Math.Max(5, currentView.GetScreenCoordinateY(Y) - 25)));


            }

            if (e.Y > AxisScreenY - 5 && e.Y < AxisScreenY + 5 && !EditedX && !InteractionInUse && DrawAxisX)
            {
                graph.DrawLine(new Pen(Color.Red, 2),
                               0, currentView.GetScreenCoordinateY(Y),
                               currentView.Width, currentView.GetScreenCoordinateY(Y));

                graph.DrawString("Y: " + Math.Round(Y, 4),
                                 igpSettings.Singleton.ChartFont,
                                 lineBrush,
                                 Math.Min(currentView.Width - 50, Math.Max(25, currentView.GetScreenCoordinateX(X) + 10)),
                                 Math.Min(currentView.Height - 25, Math.Max(15, currentView.GetScreenCoordinateY(Y) - 15)));

            }

            double DoubleVectorX = !View.LogScaleX ? VectorX/View.VDistanceX : VectorX/View.VLogDistanceX;
            double DoubleVectorY = !View.LogScaleY ? VectorY/View.VDistanceY : VectorY/View.VLogDistanceY;

            if (EditedY) if (!View.LogScaleX)
            {
                XCoordinateLinear = linXo - DoubleVectorX;
            }
            else
            {
                XCoordinateLogarythmic = Math.Pow(10, (Math.Log10(logXo) - DoubleVectorX / 10));
            }

            if (EditedX) if (!View.LogScaleY)
            {
                YCoordinateLinear = linYo + DoubleVectorY;
            }
            else
            {
                YCoordinateLogarythmic = Math.Pow(10, (Math.Log10(logYo) + DoubleVectorY / 10));
            }
        }

        /// <summary>
        /// This method is required for item's reaction to mouse buttons being released. 
        /// </summary>
        /// <param name="graph">Graphics object that can be used to paint something on the screen</param>
        /// <param name="e">Mouse Event Details</param>
        public override void InteractUp(Graphics graph, MouseEventArgs e)
        {
            base.InteractUp(graph, e);

            if (EditedX || EditedY) FormMain.Singleton.EditorWindow.ReadViewProperities();

            EditedX = false;
            EditedY = false;
            InteractionInUse = true;
        }

        /// <summary>
        /// Saves axes data to a TextWriter object.
        /// </summary>
        /// <param name="sw">Settings output</param>
        public override void SaveData(TextWriter sw)
        {
            sw.WriteLine("<axes>");
            sw.WriteLine("linx = {0}", XCoordinateLinear);
            sw.WriteLine("liny = {0}", YCoordinateLinear);
            sw.WriteLine("logx = {0}", XCoordinateLogarythmic);
            sw.WriteLine("logy = {0}", YCoordinateLogarythmic);

            sw.WriteLine("drawaxisx = {0}", DrawAxisX);
            sw.WriteLine("drawaxisy = {0}", DrawAxisY);
            sw.WriteLine("lcolor = {0}", LineColor.ToArgb());
            sw.WriteLine("</axes>");
        }

        /// <summary>
        /// Loads data from a TextReader object.
        /// </summary>
        /// <param name="sr">Setting input</param>
        public override void ReadData(TextReader sr)
        {
            String line;
            
            while ((line = sr.ReadLine()) != "</axes>")
            {
                char[] sep = { '=' };
                String[] cmd = line.Split(sep, 2);

                if (cmd[0].StartsWith("linx"))
                {
                    XCoordinateLinear = double.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("liny"))
                {
                    YCoordinateLinear = double.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("logx"))
                {
                    XCoordinateLogarythmic = double.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("logy"))
                {
                    YCoordinateLogarythmic = double.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("drawaxisx"))
                {
                    DrawAxisX = bool.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("drawaxisy"))
                {
                    DrawAxisY = bool.Parse(cmd[1]);
                }

                if (cmd[0].StartsWith("lcolor"))
                {
                    LineColor = Color.FromArgb(int.Parse(cmd[1]));
                }
            }
        }
    }
}